package com.gxsoft.coll.ftputil;

import com.gxsoft.coll.dateutils.DateUtils;
import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.util.StringUtils;
import java.io.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Predicate;

/**
 * sftp工具类
 *
 * @author gxsoft
 * @date 2019-7-10
 * @time 下午1:39:44
 * @version 1.0
 */
@Slf4j
public class SFTPUtil
{
    //private static Logger log = Logger.getLogger(SFTPUtil.class.getName());

    private String host;//服务器连接ip
    private String username;//用户名
    private String password;//密码
    private int port = 22;//端口号
    private ChannelSftp sftp = null;
    private Session sshSession = null;
    private boolean isOverwrite = false;
    public SFTPUtil(){}

    public SFTPUtil(String host, int port, String username, String password)
    {
        this.host = host;
        this.username = username;
        this.password = password;
        this.port = port;
    }

    public SFTPUtil(String host, String username, String password)
    {
        this.host = host;
        this.username = username;
        this.password = password;
    }

    /**
     * 通过SFTP连接服务器
     */
    public void connect()
    {
        try
        {
            JSch jsch = new JSch();
            jsch.getSession(username, host, port);
            sshSession = jsch.getSession(username, host, port);
            if (log.isInfoEnabled())
            {
                log.info("Session created.");
            }
            sshSession.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect();
            if (log.isInfoEnabled())
            {
                log.info("Session connected.");
            }
            Channel channel = sshSession.openChannel("sftp");
            channel.connect();
            if (log.isInfoEnabled())
            {
                log.info("Opening Channel.");
            }
            sftp = (ChannelSftp) channel;
            if (log.isInfoEnabled())
            {
                log.info("Connected to " + host + ".");
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    /**
     * 关闭连接
     */
    public void disconnect()
    {
        if (this.sftp != null)
        {
            if (this.sftp.isConnected())
            {
                this.sftp.disconnect();
                if (log.isInfoEnabled())
                {
                    log.info("sftp is closed already");
                }
            }
        }
        if (this.sshSession != null)
        {
            if (this.sshSession.isConnected())
            {
                this.sshSession.disconnect();
                if (log.isInfoEnabled())
                {
                    log.info("sshSession is closed already");
                }
            }
        }
    }



    /**
     * 批量下载文件
     * @param remotePath：远程下载目录(以路径符号结束,可以为相对路径eg:/assess/sftp/jiesuan_2/2014/)
     * @param localPath：本地保存目录(以路径符号结束,D:\Duansha\sftp\)
     * @param fileFormat：下载文件格式(以特定字符开头,为空不做检验)
     * @param fileEndFormat：下载文件格式(文件格式)
     * @param del：下载后是否删除sftp文件
     * @return
     */

    public List<String> batchDownLoadFile(String remotePath, String localPath,
                                          String fileFormat, String fileEndFormat, boolean del,String intervalMinutes,String checkSuccessData)
    {
        if( StringUtils.isEmpty(remotePath) || StringUtils.isEmpty(localPath) ) {
            log.error("source  file path is not exists or target file path is not exists");
            return null ;
        }
        List<String> filenames = new ArrayList<String>();

        try
        {
            int i1 = Integer.parseInt(intervalMinutes);

            for(int i =i1; i>=1 ; i--){

            Date date  = new Date();
            Long ii = date.getTime()-(i*60*1000);

            SimpleDateFormat format =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String d = format.format(ii);
            Date now=null;
            try {
                now=  format.parse(d);
            } catch (ParseException e) {
                e.printStackTrace();
            }

              // 生成时间并且校验成功并且保存数据地址
                String path = getLocalPathFilePath(checkSuccessData,now,i+"");
                path = path.replace("\\","/");
                System.out.printf("本地地址：=="+path);
                /** 获取本地文件 */

                List<String> localFileList = getAllFile(path);

                // 利用多线程把上传开始时间
//                writeData(now,localFileList.size(),"1");

                if(localFileList.size() > 0 && localFileList.size() ==60){
                    System.out.printf("数据正常");
                    filenames = new ArrayList<>();
                }else{
                    filenames = getSourceFiles(filenames,remotePath,now,path,fileFormat,fileEndFormat,del,localFileList,intervalMinutes,localPath);

                }
            }

        }
        catch (SftpException e)
        {
            e.printStackTrace();
        }
        finally
        {
            // this.disconnect();
        }
        return filenames;
    }

    // 利用多线程把上传开始时间
//    public void writeData(Date now, int size,String dateType){
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//
//                File f = new File("logs/index/date_index.txt");
//                BufferedWriter bw = null;
//                //打印出相对路径
//                System.out.println("相对路径======"+f.getAbsolutePath());
//                try {
//                    bw = new BufferedWriter(new FileWriter(f.getAbsolutePath(),true));
//                    if("1".equals(dateType)){
//                        bw.write("开始时间："+DateUtils.fomatDate3(now)+"本地数据："+size);
//                    }else{
//                        bw.write("开始时间："+DateUtils.fomatDate3(now)+"服务器文件数量："+size);
//                    }
//
//                    bw.newLine();//换行
//
//
//                } catch (IOException e) {
//                    e.printStackTrace();
//                    log.error("写入索引文件失败：{}",e.getMessage());
//                }finally {
//                    try {
//                        bw.close();
//                    } catch (IOException e) {
//                        e.printStackTrace();
//                    }
//                }
//            }
//        }).start();
//    }

    /**  获取*/
    private List<String> getSourceFiles(List<String> filenames, String remotePath, Date now, String path,String fileFormat,
                                        String fileEndFormat, boolean del,List<String> localFileList,String intervalMinutes,String localPath) throws SftpException {
        String paths = getLocalPathFilePath(remotePath,now,intervalMinutes);
        paths =     paths.replace("\\","/");

        // connect();
        Vector v = listFiles(paths,now);
        // 异步数据处理
//        writeData(now,v.size(),"0");
        // sftp.cd(remotePath);
        if (v.size() > 0)
        {
            System.out.println("本次处理文件个数不为零,开始下载...fileSize=" + v.size());
            Iterator it = v.iterator();
            while (it.hasNext()) {
                ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry) it.next();
                String filename = entry.getFilename();
                SftpATTRS attrs = entry.getAttrs();

                if(localFileList.size() >0){
                    for (String fileUrl : localFileList) {
                        if(fileUrl.contains(filename)){
                            log.info("文件已经采集过，fileName="+filename);
                            continue;
                        }
                    }
                }

//                if(isDirExist(path+filename) ){
                if(isDirExist(path+filename) ){
                    log.info("文件已经采集过，fileName="+filename);
                    System.out.println("文件已经采集过，fileName="+filename);
                    continue;
                }
                if (!attrs.isDir()) {
                        boolean flag = false;
                        String localFileName = paths + filename;
                        fileFormat = fileFormat == null ? "" : fileFormat
                                .trim();
                        fileEndFormat = fileEndFormat == null ? ""
                                : fileEndFormat.trim();
                        // 三种情况
                        if (fileFormat.length() > 0 && fileEndFormat.length() > 0)
                        {
                            if (filename.startsWith(fileFormat) && filename.endsWith(fileEndFormat))
                            {
                                flag = downloadFile(paths, filename,path, filename,localPath);
                                if (flag)
                                {
                                    filenames.add(localFileName);
                                    if (flag && del)
                                    {
                                        // todo 后期数据是否要删除
//                                        deleteSFTP(remotePath, filename);
                                    }
                                }
                            }
                        }
                        else if (fileFormat.length() > 0 && "".equals(fileEndFormat))
                        {
                            if (filename.startsWith(fileFormat))
                            {
                                flag = downloadFile(paths, filename, path, filename,localPath);
                                if (flag)
                                {
                                    filenames.add(localFileName);
                                    if (flag && del)
                                    {
                                        // todo 后期数据是否要删除
//                                        deleteSFTP(remotePath, filename);
                                    }
                                }
                            }
                        }
                        else if (fileEndFormat.length() > 0 && "".equals(fileFormat))
                        {
                            if (filename.endsWith(fileEndFormat))
                            {
                                flag = downloadFile(paths, filename,path, filename,localPath);
                                if (flag)
                                {
                                    filenames.add(localFileName);
                                    if (flag && del)
                                    {
                                        // todo 后期数据是否要删除
//                                        deleteSFTP(remotePath, filename);
                                    }
                                }
                            }
                        }
                        else
                        {
                            flag = downloadFile(paths, filename,path, filename,localPath);
                            if (flag)
                            {
                                filenames.add(localFileName);
                                if (flag && del)
                                {
                                    // todo 后期数据是否要删除
//                                    deleteSFTP(remotePath, filename);
                                }
                            }
                        }
                    }
            }

        }
        if (log.isInfoEnabled())
        {
            log.info("download file is success:remotePath=" + remotePath
                    + "and localPath=" + paths + ",file size is"
                    + v.size());
        }
        return filenames;
    }



    /** 当前时间拼接路径
     *
     * E:\\logs\\2021\\04\\06\\11\\50")
     * */
    private String getLocalPathFilePath(String localPath, Date lastHourDate,String intervalMinutes) {

        String year = DateUtils.getYear(lastHourDate);
        String month = DateUtils.getMonth(lastHourDate);
        String day = DateUtils.getDay(lastHourDate);
        String hh = DateUtils.getHH(lastHourDate);
        String mm = DateUtils.getmm(lastHourDate);
        String filePath  = localPath +
                File.separator + year +
                File.separator + month +
                File.separator + day +
                File.separator + hh +
                File.separator + mm +
//                File.separator + mm +
//                File.separator + mm+
                File.separator;
        return filePath;

    }



    /**
     * 下载单个文件
     * @param remotePath：远程下载目录(以路径符号结束)
     * @param remoteFileName：下载文件名
     * @param localPath：本地保存目录(以路径符号结束)
     * @param localFileName：保存文件名
     * @return
     */
    public boolean downloadFile(String remotePath, String remoteFileName,String path, String localFileName,String localPath)
    {
        FileOutputStream fieloutput = null;
        try
        {
            // sftp.cd(remotePath);  // 把文件带日期的形式下载 如 /2021/04/06/00/12/文件名称
            // 下载到ftp 可以扫到文件的目录
            File file = new File(localPath + localFileName);
            // 文件如果已经存在 是否覆盖
            if(file.exists()){
                log.info("File is exists : "+localFileName);
                return false;
            }
            // 创建本地文件夹
            mkdirs(localPath + localFileName);
            fieloutput = new FileOutputStream(file);
            // 把线上服务的文件内容写到 本地数如流里面
            sftp.get(remotePath + remoteFileName, fieloutput);

            if (log.isInfoEnabled())
            {
                log.info("===DownloadFile:" + remoteFileName + " success from sftp.");
            }
            return true;
        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
        catch (SftpException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != fieloutput)
            {
                try
                {
                    fieloutput.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    /**
     * 上传单个文件
     * @param remotePath：远程保存目录
     * @param remoteFileName：保存文件名
     * @param localPath：本地上传目录(以路径符号结束)
     * @param localFileName：上传的文件名
     * @return
     */
    public boolean uploadFile(String remotePath, String remoteFileName,String localPath, String localFileName)
    {
        FileInputStream in = null;
        try
        {
            createDir(remotePath);
            File file = new File(localPath + localFileName);
            in = new FileInputStream(file);
            sftp.put(in, remoteFileName);
            return true;
        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
        catch (SftpException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (in != null)
            {
                try
                {
                    in.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    /**
     * 批量上传文件
     * @param remotePath：远程保存目录
     * @param localPath：本地上传目录(以路径符号结束)
     * @param fileFormat：下载文件格式(以特定字符开头,为空不做检验)
     * @param fileEndFormat：下载文件格式(文件格式)
     * @param del：上传后是否删除本地文件
     *
     * @return
     */
    public boolean bacthUploadFile(String remotePath, String localPath,String fileFormat,String fileEndFormat,
                                   boolean del, String backupPath)
    {
        try
        {
            connect();
            File file = new File(localPath);
            File[] files = file.listFiles();
            for (int i = 0; i < files.length; i++)
            {
                if(! files[i].isFile()){
                   continue;
                }
                if( ! StringUtils.isEmpty(fileFormat)
                        && !files[i].getName().startsWith(fileFormat)){
                    continue;
                }
                if( ! StringUtils.isEmpty(fileEndFormat)
                        && !files[i].getName().startsWith(fileEndFormat)){
                    continue;
                }

                if (this.uploadFile(remotePath, files[i].getName(),
                        localPath, files[i].getName())
                        && del)
                {
                    deleteFile(localPath + files[i].getName());
                }


            }
            if (log.isInfoEnabled())
            {
                log.info("upload file is success:remotePath=" + remotePath
                        + "and localPath=" + localPath + ",file size is "
                        + files.length);
            }
            return true;
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            this.disconnect();
        }
        return false;

    }

    /**
     * 删除本地文件
     * @param filePath
     * @return
     */
    public boolean deleteFile(String filePath)
    {
        File file = new File(filePath);
        if (!file.exists())
        {
            return false;
        }

        if (!file.isFile())
        {
            return false;
        }
        boolean rs = file.delete();
        if (rs && log.isInfoEnabled())
        {
            log.info("delete file success from local.");
        }
        return rs;
    }

    /**
     * 创建目录
     * @param createpath
     * @return
     */
    public boolean createDir(String createpath)
    {
        try
        {
            if (isDirExist(createpath))
            {
                this.sftp.cd(createpath);
                return true;
            }
            String pathArry[] = createpath.split("/");
            StringBuffer filePath = new StringBuffer("/");
            for (String path : pathArry)
            {
                if (path.equals(""))
                {
                    continue;
                }
                filePath.append(path + "/");
                if (isDirExist(filePath.toString()))
                {
                    sftp.cd(filePath.toString());
                }
                else
                {
                    // 建立目录
                    sftp.mkdir(filePath.toString());
                    // 进入并设置为当前目录
                    sftp.cd(filePath.toString());
                }

            }
            this.sftp.cd(createpath);
            return true;
        }
        catch (SftpException e)
        {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 判断目录是否存在
     * @param directory
     * @return
     */
    public boolean isDirExist(String directory)
    {
        boolean isDirExistFlag = false;
        try
        {
            SftpATTRS sftpATTRS = sftp.lstat(directory);
            isDirExistFlag = true;
            return sftpATTRS.isDir();
        }
        catch (Exception e)
        {
            if (e.getMessage().toLowerCase().equals("no such file"))
            {
                isDirExistFlag = false;
            }
        }
        return isDirExistFlag;
    }

    /**
     * 判断文件是否存在
     * @param fullFileName
     */
    public boolean judeFileExists(String fullFileName) {

        File file = new File(fullFileName);
        return file.exists();
    }
    /**
     * 删除stfp文件
     * @param directory：要删除文件所在目录
     * @param deleteFile：要删除的文件
     */
    public void deleteSFTP(String directory, String deleteFile)
    {
        try
        {
            // sftp.cd(directory);
            sftp.rm(directory + deleteFile);
            if (log.isInfoEnabled())
            {
                log.info("delete file success from sftp.");
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    /**
     * 如果目录不存在就创建目录
     * @param path
     */
    public void mkdirs(String path)
    {
        File f = new File(path);

        String fs = f.getParent();

        f = new File(fs);

        if (!f.exists())
        {
            f.mkdirs();
        }
    }
    /**
     * 文件重命名
     * @param oldPath
     * @param newPath
     */
    public void rename(String oldPath, String newPath)
    {
        try {
            sftp.rename(oldPath,newPath);
        } catch (SftpException e) {
            log.error("File rename failed ["+oldPath+"]->["+newPath+"]");
        }
    }

    /**
     * 列出目录下的文件
     *
     * @param directory：要列出的目录
     * @return
     * @throws SftpException
     */
    public Vector listFiles(String directory,Date now) throws SftpException {
        Vector vector = new Vector();
        /**
         * 过滤linux目录下 '.' 和 '..' 文件
         * */
        boolean  isExist = isExistDir(directory);
        if(!isExist){
//
//            String BAYONET_PATH = this.getClass().getClassLoader().getResource("record_log.txt").getPath();
//            FileWriter fw = null;
//            try {
//                //创建字符输出流对象，负责向文件内写入
//                fw = new FileWriter("D:\\working\\scadaSecs\\06.newScadaSecs\\scadaSecsReCollect\\src\\main\\resources\\record_log.txt",true);
//                String date3 = DateUtils.fomatDate3(now);
//                fw.write("服务器在该时间:"+date3+"===不存在目录和数据===="+directory+"\r\n");
//            } catch (IOException e) {
//                e.printStackTrace();
//            }finally{
//                if(fw!=null){
//                    try {
//                        fw.close();
//                    } catch (IOException e) {
//                        e.printStackTrace();
//                    }
//                }
//            }
            log.info("服务器上不存在文件:{}",directory);
        }else{
             vector =  sftp.ls(directory);
            vector.removeIf(new Predicate<ChannelSftp.LsEntry>() {
                @Override
                public boolean test(ChannelSftp.LsEntry lsEntry) {
                    return "..".equals(lsEntry.getFilename()) || "src/main".equals(lsEntry.getFilename()) || ".".equals(lsEntry.getFilename());
                }
            });
        }





        return vector;
    }


    public boolean isExistDir(String path){
        boolean  isExist=false;
        try {
            SftpATTRS sftpATTRS = sftp.lstat(path);
            isExist = true;
            return sftpATTRS.isDir();
        } catch (Exception e) {
            if (e.getMessage().toLowerCase().equals("no such file")) {
                isExist = false;
            }
        }
        return isExist;

    }

    /** 获取本地文件*/
    public static  List<String> getAllFile(String directoryPath) {
        List<String> list = new ArrayList<String>();
        File baseFile = new File(directoryPath);
        if (baseFile.isFile() || !baseFile.exists()) {
            return list;
        }
        File[] files = baseFile.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                    list.add(file.toString());
//                    list.add(file.getAbsolutePath());
//                list.addAll(getAllFile(file.getAbsolutePath()));
            } else {
                list.add(file.toString());
//                list.add(file.getAbsolutePath());
            }
        }
        return list;
    }

    public String getHost()
    {
        return host;
    }

    public void setHost(String host)
    {
        this.host = host;
    }

    public String getUsername()
    {
        return username;
    }

    public void setUsername(String username)
    {
        this.username = username;
    }

    public String getPassword()
    {
        return password;
    }

    public void setPassword(String password)
    {
        this.password = password;
    }

    public int getPort()
    {
        return port;
    }

    public void setPort(int port)
    {
        this.port = port;
    }

    public ChannelSftp getSftp()
    {
        return sftp;
    }

    public void setSftp(ChannelSftp sftp)
    {
        this.sftp = sftp;
    }


}